diff --git a/include/asterisk/core_local.h b/include/asterisk/core_local.h
index 8557072c69bfd81cb1fc909b7514b90f7c03377f..7d66983369a2feb9e1405f31ff491741af7a4c12 100644
--- a/include/asterisk/core_local.h
+++ b/include/asterisk/core_local.h
@@ -45,6 +45,8 @@ 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.
  *
+ * \deprecated - *DO NOT USE* Please use ast_local_lock_all2 instead.
+ *
  * \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.
@@ -59,10 +61,29 @@ struct stasis_message_type;
 void ast_local_lock_all(struct ast_channel *chan, struct ast_channel **outchan,
 			struct ast_channel **outowner);
 
+/*!
+ * \brief Add a reference to the local channel's private tech, lock the local channel's
+ *        private base, and add references and lock both sides of the local channel.
+ *
+ * \note None of these locks should be held prior to calling this function.
+ * \note To undo this process call ast_local_unlock_all2.
+ *
+ * \since 13.17.0, 14.6.0
+ *
+ * \param chan Must be a local channel
+ * \param tech_pvt [out] channel's private tech (ref and lock added)
+ * \param base_chan [out] One side of the local channel (ref and lock added)
+ * \param base_owner [out] Other side of the local channel (ref and lock added)
+ */
+void ast_local_lock_all2(struct ast_channel *chan, void **tech_pvt,
+	struct ast_channel **base_chan, struct ast_channel **base_owner);
+
 /*!
  * \brief Unlock the "chan" and "owner" channels on the base private structure
  *        as well as the base private structure itself.
  *
+ * \deprecated - *DO NOT USE* Please use ast_local_unlock_all2 instead.
+ *
  * \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.
@@ -73,6 +94,22 @@ void ast_local_lock_all(struct ast_channel *chan, struct ast_channel **outchan,
  */
 void ast_local_unlock_all(struct ast_channel *chan);
 
+/*!
+ * \brief Remove a reference to the given local channel's private tech, unlock the given
+ *        local channel's private base, and remove references and unlock both sides of
+ *        given the local channel.
+ *
+ * \note This function should be used in conjunction with ast_local_lock_all2.
+ *
+ * \since 13.17.0, 14.6.0
+ *
+ * \param tech_pvt channel's private tech (ref and lock removed)
+ * \param base_chan One side of the local channel (ref and lock removed)
+ * \param base_owner Other side of the local channel (ref and lock removed)
+ */
+void ast_local_unlock_all2(void *tech_pvt, struct ast_channel *base_chan,
+	struct ast_channel *base_owner);
+
 /*!
  * \brief Get the other local channel in the pair.
  * \since 12.0.0
diff --git a/main/bridge.c b/main/bridge.c
index b2beb86377ff09d3c875a5fba82f9965005c773c..b812ac89f938db9f70795730ec0e4d5086739a88 100644
--- a/main/bridge.c
+++ b/main/bridge.c
@@ -4241,14 +4241,15 @@ static enum ast_transfer_result attended_transfer_bridge(struct ast_channel *cha
 	BRIDGE_LOCK_ONE_OR_BOTH(bridge1, bridge2);
 
 	if (bridge2) {
+		void *tech;
 		struct ast_channel *locals[2];
 
 		/* Have to lock everything just in case a hangup comes in early */
-		ast_local_lock_all(local_chan, &locals[0], &locals[1]);
+		ast_local_lock_all2(local_chan, &tech, &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);
+			ast_local_unlock_all2(tech, locals[0], locals[1]);
 			ao2_cleanup(local_chan);
 			return AST_BRIDGE_TRANSFER_FAIL;
 		}
@@ -4259,7 +4260,7 @@ static enum ast_transfer_result attended_transfer_bridge(struct ast_channel *cha
 		}
 
 		ast_attended_transfer_message_add_link(transfer_msg, locals);
-		ast_local_unlock_all(local_chan);
+		ast_local_unlock_all2(tech, locals[0], locals[1]);
 	} 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 1b8ebf6f1ea8082353ff160e3c8a98b691cadc8b..a5918f525ca0f111b2648569300053aad463ddb3 100644
--- a/main/core_local.c
+++ b/main/core_local.c
@@ -235,17 +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)
+void ast_local_lock_all2(struct ast_channel *chan, void **tech_pvt,
+	struct ast_channel **base_chan, struct ast_channel **base_owner)
 {
 	struct local_pvt *p = ast_channel_tech_pvt(chan);
 
-	*outchan = NULL;
-	*outowner = NULL;
+	*tech_pvt = NULL;
+	*base_chan = NULL;
+	*base_owner = NULL;
 
 	if (p) {
-		ao2_ref(p, 1);
-		ast_unreal_lock_all(&p->base, outchan, outowner);
+		*tech_pvt = ao2_bump(p);
+		ast_unreal_lock_all(&p->base, base_chan, base_owner);
+	}
+}
+
+void ast_local_lock_all(struct ast_channel *chan, struct ast_channel **outchan,
+			struct ast_channel **outowner)
+{
+	void *tech_pvt;
+	ast_local_lock_all2(chan, &tech_pvt, outchan, outowner);
+}
+
+void ast_local_unlock_all2(void *tech_pvt, struct ast_channel *base_chan,
+	struct ast_channel *base_owner)
+{
+	if (base_chan) {
+		ast_channel_unlock(base_chan);
+		ast_channel_unref(base_chan);
+	}
+
+	if (base_owner) {
+		ast_channel_unlock(base_owner);
+		ast_channel_unref(base_owner);
+	}
+
+	if (tech_pvt) {
+		struct local_pvt *p = tech_pvt;
+		ao2_unlock(&p->base);
+		ao2_ref(tech_pvt, -1);
 	}
 }
 
@@ -259,19 +287,7 @@ void ast_local_unlock_all(struct ast_channel *chan)
 	}
 
 	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);
+	ast_local_unlock_all2(p, base->chan, base->owner);
 }
 
 struct ast_channel *ast_local_get_peer(struct ast_channel *ast)