diff --git a/src/core/surface/call.c b/src/core/surface/call.c
index 5e3f581509e7a2ffb2e9e4c87099fbd017faa01d..8fb42e29bef25711a28535fb0dff74a18d7ecdd1 100644
--- a/src/core/surface/call.c
+++ b/src/core/surface/call.c
@@ -183,8 +183,9 @@ legacy_state *get_legacy_state(grpc_call *call) {
 
 void grpc_call_internal_ref(grpc_call *c) { gpr_ref(&c->internal_refcount); }
 
-static void destroy_call(grpc_call *c) {
+static void destroy_call(void *call, int ignored_success) {
   int i;
+  grpc_call *c = call;
   grpc_call_stack_destroy(CALL_STACK_FROM_CALL(c));
   grpc_channel_internal_unref(c->channel);
   gpr_mu_destroy(&c->mu);
@@ -203,9 +204,13 @@ static void destroy_call(grpc_call *c) {
   gpr_free(c);
 }
 
-void grpc_call_internal_unref(grpc_call *c) {
+void grpc_call_internal_unref(grpc_call *c, int allow_immediate_deletion) {
   if (gpr_unref(&c->internal_refcount)) {
-    destroy_call(c);
+    if (allow_immediate_deletion) {
+      destroy_call(c, 1);
+    } else {
+      grpc_iomgr_add_callback(destroy_call, c);
+    }
   }
 }
 
@@ -350,7 +355,7 @@ static void finish_write_step(void *pc, grpc_op_error error) {
   }
   call->sending = 0;
   unlock(call);
-  grpc_call_internal_unref(call);
+  grpc_call_internal_unref(call, 0);
 }
 
 static void finish_finish_step(void *pc, grpc_op_error error) {
@@ -359,7 +364,7 @@ static void finish_finish_step(void *pc, grpc_op_error error) {
   finish_ioreq_op(call, GRPC_IOREQ_SEND_CLOSE, error);
   call->sending = 0;
   unlock(call);
-  grpc_call_internal_unref(call);
+  grpc_call_internal_unref(call, 0);
 }
 
 static void finish_start_step(void *pc, grpc_op_error error) {
@@ -368,7 +373,7 @@ static void finish_start_step(void *pc, grpc_op_error error) {
   finish_ioreq_op(call, GRPC_IOREQ_SEND_INITIAL_METADATA, error);
   call->sending = 0;
   unlock(call);
-  grpc_call_internal_unref(call);
+  grpc_call_internal_unref(call, 0);
 }
 
 static send_action choose_send_action(grpc_call *call) {
@@ -464,7 +469,7 @@ static void enact_send_action(grpc_call *call, send_action sa) {
       lock(call);
       call->sending = 0;
       unlock(call);
-      grpc_call_internal_unref(call);
+      grpc_call_internal_unref(call, 0);
       break;
     case SEND_FINISH:
       if (!call->is_client) {
@@ -656,7 +661,7 @@ void grpc_call_destroy(grpc_call *c) {
   cancel = !c->stream_closed;
   unlock(c);
   if (cancel) grpc_call_cancel(c);
-  grpc_call_internal_unref(c);
+  grpc_call_internal_unref(c, 1);
 }
 
 grpc_call_error grpc_call_cancel(grpc_call *c) {
@@ -958,7 +963,7 @@ static void call_alarm(void *arg, int success) {
       grpc_call_cancel(call);
     }
   }
-  grpc_call_internal_unref(call);
+  grpc_call_internal_unref(call, 1);
 }
 
 void grpc_call_set_deadline(grpc_call_element *elem, gpr_timespec deadline) {
@@ -998,7 +1003,7 @@ void grpc_call_stream_closed(grpc_call_element *elem) {
     finish_ioreq_op(call, GRPC_IOREQ_RECV_STATUS, GRPC_OP_OK);
   }
   unlock(call);
-  grpc_call_internal_unref(call);
+  grpc_call_internal_unref(call, 0);
 }
 
 /* we offset status by a small amount when storing it into transport metadata
diff --git a/src/core/surface/call.h b/src/core/surface/call.h
index 57592089eef7740313eb29a0dd956f120a172fdd..c130a13b81d3d4f5ee7c906499c8dc76127d0850 100644
--- a/src/core/surface/call.h
+++ b/src/core/surface/call.h
@@ -46,7 +46,7 @@ grpc_call *grpc_call_create(grpc_channel *channel,
                             const void *server_transport_data);
 
 void grpc_call_internal_ref(grpc_call *call);
-void grpc_call_internal_unref(grpc_call *call);
+void grpc_call_internal_unref(grpc_call *call, int allow_immediate_deletion);
 
 /* Helpers for grpc_client, grpc_server filters to publish received data to
    the completion queue/surface layer */
diff --git a/src/core/surface/completion_queue.c b/src/core/surface/completion_queue.c
index 5854afbeefdf67216eab8f51a7adb1578f3e087a..ae3b96035c17a0eaba1454eef18da9e32febf6b5 100644
--- a/src/core/surface/completion_queue.c
+++ b/src/core/surface/completion_queue.c
@@ -388,7 +388,7 @@ void grpc_event_finish(grpc_event *base) {
   event *ev = (event *)base;
   ev->on_finish(ev->on_finish_user_data, GRPC_OP_OK);
   if (ev->base.call) {
-    grpc_call_internal_unref(ev->base.call);
+    grpc_call_internal_unref(ev->base.call, 1);
   }
   gpr_free(ev);
 }