diff --git a/api/docs/bt.dox b/api/docs/bt.dox
index 1ae0c7f96f2ebe538b1e39b196633222ec32eeea..4b347c6b84e88d425aad3556d27d9df2b0858adb 100644
--- a/api/docs/bt.dox
+++ b/api/docs/bt.dox
@@ -500,6 +500,8 @@ internal operation requires that we impose the following limitations:
    a basic block, and it must be the final application branch in the block.
  - The exit control-flow of a block ending in a system call cannot be
    changed.
+ - On AArch64, an ISB instruction (#OP_isb) must be the last instruction
+   in its block.
 
 Application instructions, or non-meta instructions, in addition to being
 processed (and followed if control flow), are also considered safe points
diff --git a/core/arch/interp.c b/core/arch/interp.c
index 0c992e91fe6a91bea50b0674c3469df9658f543a..d1ac010960b50aa5477103dc326c8ce187f6c24c 100644
--- a/core/arch/interp.c
+++ b/core/arch/interp.c
@@ -2907,6 +2907,13 @@ client_process_bb(dcontext_t *dcontext, build_bb_t *bb)
                       "block's app sources (instr_set_translation() targets) "
                       "must remain within original bounds");
 
+# ifdef AARCH64
+        if (instr_get_opcode(inst) == OP_isb) {
+            CLIENT_ASSERT(inst == instrlist_last(bb->ilist),
+                          "OP_isb must be last instruction in block");
+        }
+# endif
+
         /* PR 307284: we didn't process syscalls and ints pre-client
          * so do so now to get bb->flags and bb->exit_type set
          */
@@ -3920,6 +3927,11 @@ build_bb_ilist(dcontext_t *dcontext, build_bb_t *bb)
             if (!bb_process_interrupt(dcontext, bb))
                 break;
         }
+#ifdef AARCH64
+        /* OP_isb, when mangled, has a potential side exit. */
+        else if (instr_get_opcode(bb->instr) == OP_isb)
+            break;
+#endif
 #if 0/*i#1313, i#1314*/
         else if (instr_get_opcode(bb->instr) == OP_getsec) {
             /* XXX i#1313: if we support CPL0 in the future we'll need to
diff --git a/core/arch/mangle_shared.c b/core/arch/mangle_shared.c
index 513c9253ccec67e24b9637f2fe8ed1e706ddb7a4..52b1486c54315e29d8bc55748a7a592313daad34 100644
--- a/core/arch/mangle_shared.c
+++ b/core/arch/mangle_shared.c
@@ -908,7 +908,7 @@ mangle(dcontext_t *dcontext, instrlist_t *ilist, uint *flags INOUT,
 #ifdef AARCH64
         if (instr_is_icache_op(instr) && instr_is_app(instr)) {
             next_instr = mangle_icache_op(dcontext, ilist, instr, next_instr,
-                                          get_app_instr_xl8(next_instr));
+                                          get_app_instr_xl8(instr) + AARCH64_INSTR_SIZE);
             continue;
         }
 #endif
diff --git a/core/lib/instrument_api.h b/core/lib/instrument_api.h
index 9f15ce884985a0b648d9457f7fbf14d6092042cd..c513e10eacc3600cfd31aa60312916620165e87e 100644
--- a/core/lib/instrument_api.h
+++ b/core/lib/instrument_api.h
@@ -221,6 +221,8 @@ DR_API
  * - A system call or interrupt instruction can only be added
  * if it satisfies the above constraints: i.e., if it is the final
  * instruction in the block and the only system call or interrupt.
+ * - Any AArch64 #OP_isb instruction must be the last instruction
+ * in its block.
  * - All IT blocks must be legal.  For example, application instructions
  * inside an IT block cannot be removed or added to without also
  * updating the OP_it instruction itself.  Clients can use