diff --git a/main/stasis_channels.c b/main/stasis_channels.c
index d40b5701cb64d35c5825d4c1de3e64e08c161f21..79c453cdd328283026b15b45eed6d4d7032041f5 100644
--- a/main/stasis_channels.c
+++ b/main/stasis_channels.c
@@ -40,6 +40,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/stasis.h"
 #include "asterisk/stasis_cache_pattern.h"
 #include "asterisk/stasis_channels.h"
+#include "asterisk/dial.h"
+#include "asterisk/linkedlists.h"
 
 /*** DOCUMENTATION
 	<managerEvent language="en_US" name="VarSet">
@@ -360,10 +362,29 @@ void ast_channel_publish_dial_forward(struct ast_channel *caller, struct ast_cha
 	publish_message_for_channel_topics(msg, caller);
 }
 
+static void remove_dial_masquerade(struct ast_channel *caller,
+	struct ast_channel *peer);
+static int set_dial_masquerade(struct ast_channel *caller,
+	struct ast_channel *peer, const char *dialstring);
+
 void ast_channel_publish_dial(struct ast_channel *caller, struct ast_channel *peer,
 	const char *dialstring, const char *dialstatus)
 {
+	if (caller) {
+		ast_channel_lock_both(caller, peer);
+		if (!ast_strlen_zero(dialstatus)) {
+			remove_dial_masquerade(caller, peer);
+		} else {
+			set_dial_masquerade(caller, peer, dialstring);
+		}
+	}
+
 	ast_channel_publish_dial_forward(caller, peer, NULL, dialstring, dialstatus, NULL);
+
+	if (caller) {
+		ast_channel_unlock(peer);
+		ast_channel_unlock(caller);
+	}
 }
 
 static struct stasis_message *create_channel_blob_message(struct ast_channel_snapshot *snapshot,
@@ -1198,3 +1219,201 @@ int ast_stasis_channels_init(void)
 	return res;
 }
 
+/*!
+ * \internal
+ * \brief A list element for the dial_masquerade_datastore -- stores data about a dialed peer
+ */
+struct dial_target {
+	struct ast_channel *peer;
+	char *dialstring;
+	AST_LIST_ENTRY(dial_target) list;
+};
+
+/*!
+ * \internal
+ * \brief Datastore used for advancing dial state in the case of a masquerade
+ *        against a channel in the process of dialing.
+ */
+struct dial_masquerade_datastore {
+	AST_LIST_HEAD(,dial_target) dialed_peers;
+};
+
+/*!
+ * \internal
+ * \brief Destructor for dial_masquerade_datastore
+ */
+static void dial_masquerade_datastore_destroy(void *data)
+{
+	struct dial_masquerade_datastore *ds = data;
+	struct dial_target *cur;
+
+	while ((cur = AST_LIST_REMOVE_HEAD(&ds->dialed_peers, list))) {
+		ast_channel_cleanup(cur->peer);
+		ast_free(cur->dialstring);
+		ast_free(cur);
+	}
+}
+
+static void disable_dial_masquerade(struct ast_channel *caller);
+
+/*!
+ * \internal
+ * \brief Primary purpose for dial_masquerade_datastore, publishes
+ *        the channel dial event needed to set the incoming channel into the
+ *        dial state during a masquerade.
+ * \param data pointer to the dial_masquerade_datastore
+ * \param old_chan Channel being replaced (not used)
+ * \param new_chan Channel being pushed to dial mode
+ */
+static void dial_masquerade(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
+{
+	struct dial_masquerade_datastore *masq_data = data;
+	struct dial_target *cur;
+
+	AST_LIST_TRAVERSE(&masq_data->dialed_peers, cur, list) {
+		ast_channel_publish_dial_forward(old_chan, cur->peer, NULL, cur->dialstring, "NOANSWER", NULL);
+		ast_channel_publish_dial_forward(new_chan, cur->peer, NULL, cur->dialstring, NULL, NULL);
+	}
+
+	disable_dial_masquerade(old_chan);
+}
+
+static const struct ast_datastore_info dial_masquerade_info = {
+	.type = "stasis-chan-dial-masq",
+	.destroy = dial_masquerade_datastore_destroy,
+	.chan_breakdown = dial_masquerade,
+};
+
+/*!
+ * \internal
+ * \brief Retrieves the dial_masquerade_datastore from a channel if
+ *        it has one.
+ * \param chan Channel a datastore data is wanted from
+ *
+ * \returns the datastore data if it exists
+ * \returns NULL if no dial_masquerade_datastore has been set for
+ *          chan
+ */
+static struct dial_masquerade_datastore *fetch_dial_masquerade_datastore(struct ast_channel *chan)
+{
+	struct ast_datastore *datastore = NULL;
+
+	datastore = ast_channel_datastore_find(chan, &dial_masquerade_info, NULL);
+	if (!datastore) {
+		return NULL;
+	}
+
+	return datastore->data;
+}
+
+/*!
+ * \internal
+ * \brief Create a fresh dial_masquerade_datastore on a channel
+ * \param chan Channel we want to create a dial_masquerade_datastore
+ *        for.
+ * \returns pointer to the datastore data if successful
+ * \returns NULL on allocation error
+ */
+static struct dial_masquerade_datastore *setup_dial_masquerade_datastore(struct ast_channel *chan)
+{
+	struct ast_datastore *datastore = NULL;
+	struct dial_masquerade_datastore *masq_datastore;
+
+	datastore = ast_datastore_alloc(&dial_masquerade_info, NULL);
+	if (!datastore) {
+		return NULL;
+	}
+
+	masq_datastore = ast_calloc(1, sizeof(*masq_datastore));
+	if (!masq_datastore) {
+		ast_datastore_free(datastore);
+		return NULL;
+	}
+
+	datastore->data = masq_datastore;
+	ast_channel_datastore_add(chan, datastore);
+	return masq_datastore;
+}
+
+/*!
+ * \internal
+ * \brief Get existing dial_masquerade_datastore if it exists. If
+ *        not, create a new one and return a pointer to that data.
+ * \param chan Which channel the datastore is wanted for.
+ * \returns pointer to the datastore if successful
+ * \returns NULL on allocation failure.
+ */
+static struct dial_masquerade_datastore *fetch_or_create_dial_masquerade_datastore(struct ast_channel *chan)
+{
+	struct dial_masquerade_datastore *ds;
+
+	ds = fetch_dial_masquerade_datastore(chan);
+	if (!ds) {
+		ds = setup_dial_masquerade_datastore(chan);
+	}
+
+	return ds;
+}
+
+static int set_dial_masquerade(struct ast_channel *chan, struct ast_channel *peer_chan, const char *dialstring)
+{
+	struct dial_masquerade_datastore *ds = fetch_or_create_dial_masquerade_datastore(chan);
+	struct dial_target *target = ast_calloc(1, sizeof(*target));
+
+	if (!target) {
+		return -1;
+	}
+
+	if (!ds) {
+		ast_free(target);
+		return -1;
+	}
+
+	if (dialstring) {
+		target->dialstring = ast_strdup(dialstring);
+		if (!target->dialstring) {
+			ast_free(target);
+			return -1;
+		}
+	}
+
+	ast_channel_ref(peer_chan);
+	target->peer = peer_chan;
+
+	AST_LIST_INSERT_HEAD(&ds->dialed_peers, target, list);
+
+	return 0;
+}
+
+static void remove_dial_masquerade(struct ast_channel *chan, struct ast_channel *peer_chan)
+{
+	struct dial_masquerade_datastore *ds = fetch_dial_masquerade_datastore(chan);
+	struct dial_target *cur;
+
+	if (!ds) {
+		return;
+	}
+
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&ds->dialed_peers, cur, list) {
+		if (cur->peer == peer_chan) {
+			AST_LIST_REMOVE_CURRENT(list);
+			ast_channel_cleanup(cur->peer);
+			ast_free(cur->dialstring);
+			ast_free(cur);
+			break;
+		}
+	}
+	AST_LIST_TRAVERSE_SAFE_END;
+}
+
+static void disable_dial_masquerade(struct ast_channel *chan)
+{
+	struct ast_datastore *ds = ast_channel_datastore_find(chan,
+		&dial_masquerade_info, NULL);
+
+	if (!ds) {
+		return;
+	}
+
+	ast_channel_datastore_remove(chan, ds);
+}