diff --git a/main/pbx.c b/main/pbx.c
index dc4b91f08419a5fe57368f46fbdf54b225674c3b..28027c06b8ac38d4bb20903d170fbcbe26f8b8cd 100644
--- a/main/pbx.c
+++ b/main/pbx.c
@@ -7529,8 +7529,8 @@ struct pbx_outgoing {
 	int dial_res;
 	/*! \brief Set when dialing is completed */
 	unsigned int dialed:1;
-	/*! \brief Set when execution is completed */
-	unsigned int executed:1;
+	/*! \brief Set if we've spawned a thread to do our work */
+	unsigned int in_separate_thread:1;
 };
 
 /*! \brief Destructor for outgoing structure */
@@ -7553,13 +7553,19 @@ static void *pbx_outgoing_exec(void *data)
 	RAII_VAR(struct pbx_outgoing *, outgoing, data, ao2_cleanup);
 	enum ast_dial_result res;
 
-	/* Notify anyone interested that dialing is complete */
 	res = ast_dial_run(outgoing->dial, NULL, 0);
-	ao2_lock(outgoing);
-	outgoing->dial_res = res;
-	outgoing->dialed = 1;
-	ast_cond_signal(&outgoing->cond);
-	ao2_unlock(outgoing);
+
+	if (outgoing->in_separate_thread) {
+		/* Notify anyone interested that dialing is complete */
+		ao2_lock(outgoing);
+		outgoing->dial_res = res;
+		outgoing->dialed = 1;
+		ast_cond_signal(&outgoing->cond);
+		ao2_unlock(outgoing);
+	} else {
+		/* We still need the dial result, but we don't need to lock */
+		outgoing->dial_res = res;
+	}
 
 	/* If the outgoing leg was not answered we can immediately return and go no further */
 	if (res != AST_DIAL_RESULT_ANSWERED) {
@@ -7599,12 +7605,6 @@ static void *pbx_outgoing_exec(void *data)
 		}
 	}
 
-	/* Notify anyone else again that may be interested that execution is complete */
-	ao2_lock(outgoing);
-	outgoing->executed = 1;
-	ast_cond_signal(&outgoing->cond);
-	ao2_unlock(outgoing);
-
 	return NULL;
 }
 
@@ -7810,34 +7810,42 @@ static int pbx_outgoing_attempt(const char *type, struct ast_format_cap *cap,
 		}
 	}
 
+	/* This extra reference is dereferenced by pbx_outgoing_exec */
 	ao2_ref(outgoing, +1);
-	if (ast_pthread_create_detached(&thread, NULL, pbx_outgoing_exec, outgoing)) {
-		ast_log(LOG_WARNING, "Unable to spawn dialing thread for '%s/%s'\n", type, addr);
-		ao2_ref(outgoing, -1);
-		if (locked_channel) {
-			if (!synchronous) {
-				ast_channel_unlock(dialed);
+
+	if (synchronous == AST_OUTGOING_WAIT_COMPLETE) {
+		/*
+		 * Because we are waiting until this is complete anyway, there is no
+		 * sense in creating another thread that we will just need to wait
+		 * for, so instead we commandeer the current thread.
+		 */
+		pbx_outgoing_exec(outgoing);
+	} else {
+		outgoing->in_separate_thread = 1;
+
+		if (ast_pthread_create_detached(&thread, NULL, pbx_outgoing_exec, outgoing)) {
+			ast_log(LOG_WARNING, "Unable to spawn dialing thread for '%s/%s'\n", type, addr);
+			ao2_ref(outgoing, -1);
+			if (locked_channel) {
+				if (!synchronous) {
+					ast_channel_unlock(dialed);
+				}
+				ast_channel_unref(dialed);
 			}
-			ast_channel_unref(dialed);
+			return -1;
 		}
-		return -1;
-	}
 
-	if (synchronous) {
-		ao2_lock(outgoing);
-		/* Wait for dialing to complete */
-		while (!outgoing->dialed) {
-			ast_cond_wait(&outgoing->cond, ao2_object_get_lockaddr(outgoing));
-		}
-		if (1 < synchronous
-			&& outgoing->dial_res == AST_DIAL_RESULT_ANSWERED) {
-			/* Wait for execution to complete */
-			while (!outgoing->executed) {
+		if (synchronous) {
+			ao2_lock(outgoing);
+			/* Wait for dialing to complete */
+			while (!outgoing->dialed) {
 				ast_cond_wait(&outgoing->cond, ao2_object_get_lockaddr(outgoing));
 			}
+			ao2_unlock(outgoing);
 		}
-		ao2_unlock(outgoing);
+	}
 
+	if (synchronous) {
 		/* Determine the outcome of the dialing attempt up to it being answered. */
 		if (reason) {
 			*reason = pbx_dial_reason(outgoing->dial_res,