diff --git a/main/bridge_basic.c b/main/bridge_basic.c
index b5305a61fa1e06478ff59fad5bc838f8764838cc..48b791d9df1474984bb87dcfaead01168cee7915 100644
--- a/main/bridge_basic.c
+++ b/main/bridge_basic.c
@@ -45,6 +45,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/app.h"
 #include "asterisk/dial.h"
 #include "asterisk/stasis_bridges.h"
+#include "asterisk/stasis_channels.h"
 #include "asterisk/features.h"
 #include "asterisk/format_cache.h"
 #include "asterisk/test.h"
@@ -1347,6 +1348,8 @@ struct attended_transfer_properties {
 	struct ast_dial *dial;
 	/*! The bridging features the transferer has available */
 	struct ast_flags transferer_features;
+	/*! Saved transferer connected line data for recalling the transferer. */
+	struct ast_party_connected_line original_transferer_colp;
 };
 
 static void attended_transfer_properties_destructor(void *obj)
@@ -1361,6 +1364,7 @@ static void attended_transfer_properties_destructor(void *obj)
 	ast_channel_cleanup(props->transferer);
 	ast_channel_cleanup(props->transfer_target);
 	ast_channel_cleanup(props->recall_target);
+	ast_party_connected_line_free(&props->original_transferer_colp);
 	ast_string_field_free_memory(props);
 	ast_cond_destroy(&props->cond);
 }
@@ -1428,6 +1432,7 @@ static struct attended_transfer_properties *attended_transfer_properties_alloc(
 	xfer_cfg = ast_get_chan_features_xfer_config(props->transferer);
 	if (!xfer_cfg) {
 		ast_log(LOG_ERROR, "Unable to get transfer configuration from channel %s\n", ast_channel_name(props->transferer));
+		ast_channel_unlock(props->transferer);
 		ao2_ref(props, -1);
 		return NULL;
 	}
@@ -1443,11 +1448,20 @@ static struct attended_transfer_properties *attended_transfer_properties_alloc(
 	ast_string_field_set(props, failsound, xfer_cfg->xferfailsound);
 	ast_string_field_set(props, xfersound, xfer_cfg->xfersound);
 
+	/*
+	 * Save the transferee's party information for any recall calls.
+	 * This is the only piece of information needed that gets overwritten
+	 * on the transferer channel by the inital call to the transfer target.
+	 */
+	ast_party_connected_line_copy(&props->original_transferer_colp,
+		ast_channel_connected(props->transferer));
+
 	tech = ast_strdupa(ast_channel_name(props->transferer));
 	addr = strchr(tech, '/');
 	if (!addr) {
 		ast_log(LOG_ERROR, "Transferer channel name does not follow typical channel naming format (tech/address)\n");
-		ast_channel_unref(props->transferer);
+		ast_channel_unlock(props->transferer);
+		ao2_ref(props, -1);
 		return NULL;
 	}
 	*addr++ = '\0';
@@ -2331,10 +2345,50 @@ static void recall_callback(struct ast_dial *dial)
 	}
 }
 
+/*!
+ * \internal
+ * \brief Setup common things to transferrer and transfer_target recall channels.
+ *
+ * \param recall Channel for recalling a party.
+ * \param transferer Channel supplying recall information.
+ *
+ * \details
+ * Setup callid, variables, datastores, accountcode, and peeraccount.
+ *
+ * \pre Both channels are locked on entry.
+ *
+ * \pre COLP and CLID on the recall channel are setup by the caller but not
+ * explicitly published yet.
+ *
+ * \return Nothing
+ */
+static void common_recall_channel_setup(struct ast_channel *recall, struct ast_channel *transferer)
+{
+	struct ast_callid *callid;
+
+	callid = ast_read_threadstorage_callid();
+	if (callid) {
+		ast_channel_callid_set(recall, callid);
+		ast_callid_unref(callid);
+	}
+
+	ast_channel_inherit_variables(transferer, recall);
+	ast_channel_datastore_inherit(transferer, recall);
+
+	/*
+	 * Stage a snapshot to ensure that a snapshot is always done
+	 * on the recall channel so earler COLP and CLID setup will
+	 * get published.
+	 */
+	ast_channel_stage_snapshot(recall);
+	ast_channel_req_accountcodes(recall, transferer, AST_CHANNEL_REQUESTOR_REPLACEMENT);
+	ast_channel_stage_snapshot_done(recall);
+}
 
 static int recalling_enter(struct attended_transfer_properties *props)
 {
 	RAII_VAR(struct ast_format_cap *, cap, ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT), ao2_cleanup);
+	struct ast_channel *recall;
 
 	if (!cap) {
 		return -1;
@@ -2360,7 +2414,26 @@ static int recalling_enter(struct attended_transfer_properties *props)
 		return -1;
 	}
 
-	ast_dial_set_state_callback(props->dial, &recall_callback);
+	/*
+	 * Setup callid, variables, datastores, accountcode, peeraccount,
+	 * COLP, and CLID on the recalled transferrer.
+	 */
+	recall = ast_dial_get_channel(props->dial, 0);
+	if (!recall) {
+		return -1;
+	}
+	ast_channel_lock_both(recall, props->transferer);
+
+	ast_party_caller_copy(ast_channel_caller(recall),
+		ast_channel_caller(props->transferer));
+	ast_party_connected_line_copy(ast_channel_connected(recall),
+		&props->original_transferer_colp);
+
+	common_recall_channel_setup(recall, props->transferer);
+	ast_channel_unlock(recall);
+	ast_channel_unlock(props->transferer);
+
+	ast_dial_set_state_callback(props->dial, recall_callback);
 
 	ao2_ref(props, +1);
 	ast_dial_set_user_data(props->dial, props);
@@ -2487,6 +2560,20 @@ static int retransfer_enter(struct attended_transfer_properties *props)
 		return -1;
 	}
 
+	/*
+	 * Setup callid, variables, datastores, accountcode, peeraccount,
+	 * and COLP on the recalled transfer target.
+	 */
+	ast_channel_lock_both(props->recall_target, props->transferer);
+
+	ast_party_connected_line_copy(ast_channel_connected(props->recall_target),
+		&props->original_transferer_colp);
+	ast_party_id_reset(&ast_channel_connected(props->recall_target)->priv);
+
+	common_recall_channel_setup(props->recall_target, props->recall_target);
+	ast_channel_unlock(props->recall_target);
+	ast_channel_unlock(props->transferer);
+
 	if (ast_call(props->recall_target, destination, 0)) {
 		ast_log(LOG_ERROR, "Unable to place outbound call to recall target\n");
 		ast_hangup(props->recall_target);
@@ -2881,6 +2968,18 @@ static enum attended_transfer_stimulus wait_for_stimulus(struct attended_transfe
 static void *attended_transfer_monitor_thread(void *data)
 {
 	struct attended_transfer_properties *props = data;
+	struct ast_callid *callid;
+
+	/*
+	 * Set thread callid to the transferer's callid because we
+	 * are doing all this on that channel's behalf.
+	 */
+	ast_channel_lock(props->transferer);
+	callid = ast_channel_callid(props->transferer);
+	ast_channel_unlock(props->transferer);
+	if (callid) {
+		ast_callid_threadassoc_add(callid);
+	}
 
 	for (;;) {
 		enum attended_transfer_stimulus stimulus;
@@ -2913,6 +3012,11 @@ static void *attended_transfer_monitor_thread(void *data)
 
 	attended_transfer_properties_shutdown(props);
 
+	if (callid) {
+		ast_callid_unref(callid);
+		ast_callid_threadassoc_remove();
+	}
+
 	return NULL;
 }