diff --git a/include/asterisk/core_local.h b/include/asterisk/core_local.h
index 491112d2bf0a2514c0aa57c1aaf04348411bab3e..8557072c69bfd81cb1fc909b7514b90f7c03377f 100644
--- a/include/asterisk/core_local.h
+++ b/include/asterisk/core_local.h
@@ -41,6 +41,38 @@ struct stasis_message_type;
 
 /* ------------------------------------------------------------------- */
 
+/*!
+ * \brief Lock the "chan" and "owner" channels (and return them) on the base
+ *        private structure as well as the base private structure itself.
+ *
+ * \note This also adds references to each of the above mentioned elements and
+ *       also the underlying private local structure.
+ * \note None of these locks should be held prior to calling this function.
+ * \note To undo this process call ast_local_unlock_all.
+ *
+ * \since 13.8.0
+ *
+ * \param chan Must be a local channel
+ * \param outchan The local channel's "chan" channel
+ * \param outowner The local channel's "owner" channel
+ */
+void ast_local_lock_all(struct ast_channel *chan, struct ast_channel **outchan,
+			struct ast_channel **outowner);
+
+/*!
+ * \brief Unlock the "chan" and "owner" channels on the base private structure
+ *        as well as the base private structure itself.
+ *
+ * \note This also removes references to each of the above mentioned elements and
+ *       also the underlying private local structure.
+ * \note This function should be used in conjunction with ast_local_lock_all.
+ *
+ * \since 13.8.0
+ *
+ * \param chan Must be a local channel
+ */
+void ast_local_unlock_all(struct ast_channel *chan);
+
 /*!
  * \brief Get the other local channel in the pair.
  * \since 12.0.0
diff --git a/main/bridge.c b/main/bridge.c
index 77865757ea3b1505e0557dbe19a2bdaebfbd3c12..b9a436e86a5efcebe2d5a22a2fceb7ff39b24149 100644
--- a/main/bridge.c
+++ b/main/bridge.c
@@ -4034,19 +4034,25 @@ static enum ast_transfer_result attended_transfer_bridge(struct ast_channel *cha
 	BRIDGE_LOCK_ONE_OR_BOTH(bridge1, bridge2);
 
 	if (bridge2) {
-		RAII_VAR(struct ast_channel *, local_chan2, NULL, ao2_cleanup);
 		struct ast_channel *locals[2];
 
-		ast_channel_lock(local_chan);
-		local_chan2 = ast_local_get_peer(local_chan);
-		ast_channel_unlock(local_chan);
-
-		ast_assert(local_chan2 != NULL);
+		/* Have to lock everything just in case a hangup comes in early */
+		ast_local_lock_all(local_chan, &locals[0], &locals[1]);
+		if (!locals[0] || !locals[1]) {
+			ast_log(LOG_ERROR, "Transfer failed probably due to an early hangup - "
+				"missing other half of '%s'\n", ast_channel_name(local_chan));
+			ast_local_unlock_all(local_chan);
+			ao2_cleanup(local_chan);
+			return AST_BRIDGE_TRANSFER_FAIL;
+		}
 
-		locals[0] = local_chan;
-		locals[1] = local_chan2;
+		/* Make sure the peer is properly set */
+		if (local_chan != locals[0]) {
+			SWAP(locals[0], locals[1]);
+		}
 
 		ast_attended_transfer_message_add_link(transfer_msg, locals);
+		ast_local_unlock_all(local_chan);
 	} else {
 		ast_attended_transfer_message_add_app(transfer_msg, app, local_chan);
 	}
diff --git a/main/core_local.c b/main/core_local.c
index f81c71cd6145d594880ac5e7b29acbc708781692..6644aaf5094127004eb3fab6737b2d0d8f9c7f17 100644
--- a/main/core_local.c
+++ b/main/core_local.c
@@ -235,6 +235,45 @@ struct local_pvt {
 	char exten[AST_MAX_EXTENSION];
 };
 
+void ast_local_lock_all(struct ast_channel *chan, struct ast_channel **outchan,
+			struct ast_channel **outowner)
+{
+	struct local_pvt *p = ast_channel_tech_pvt(chan);
+
+	*outchan = NULL;
+	*outowner = NULL;
+
+	if (p) {
+		ao2_ref(p, 1);
+		ast_unreal_lock_all(&p->base, outchan, outowner);
+	}
+}
+
+void ast_local_unlock_all(struct ast_channel *chan)
+{
+	struct local_pvt *p = ast_channel_tech_pvt(chan);
+	struct ast_unreal_pvt *base;
+
+	if (!p) {
+		return;
+	}
+
+	base = &p->base;
+
+	if (base->owner) {
+		ast_channel_unlock(base->owner);
+		ast_channel_unref(base->owner);
+	}
+
+	if (base->chan) {
+		ast_channel_unlock(base->chan);
+		ast_channel_unref(base->chan);
+	}
+
+	ao2_unlock(base);
+	ao2_ref(p, -1);
+}
+
 struct ast_channel *ast_local_get_peer(struct ast_channel *ast)
 {
 	struct local_pvt *p = ast_channel_tech_pvt(ast);