diff --git a/ArmPkg/Include/Library/ArmLib.h b/ArmPkg/Include/Library/ArmLib.h
index 15f610d82e1d..1689f0072db6 100644
--- a/ArmPkg/Include/Library/ArmLib.h
+++ b/ArmPkg/Include/Library/ArmLib.h
@@ -613,4 +613,10 @@ ArmClearMemoryRegionReadOnly (
   IN  UINT64                    Length
   );
 
+VOID
+ArmReplaceLiveTranslationEntry (
+  IN  UINT64  *Entry,
+  IN  UINT64  Value
+  );
+
 #endif // __ARM_LIB__
diff --git a/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.inf b/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.inf
index dd585dea91fb..58684e8492f2 100644
--- a/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.inf
+++ b/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.inf
@@ -17,9 +17,10 @@ [Defines]
   INF_VERSION                    = 0x00010005
   BASE_NAME                      = AArch64Lib
   FILE_GUID                      = ef20ddf5-b334-47b3-94cf-52ff44c29138
-  MODULE_TYPE                    = DXE_DRIVER
+  MODULE_TYPE                    = BASE
   VERSION_STRING                 = 1.0
   LIBRARY_CLASS                  = ArmLib
+  CONSTRUCTOR                    = AArch64LibConstructor
 
 [Sources.AARCH64]
   AArch64Lib.c
@@ -31,6 +32,7 @@ [Sources.AARCH64]
 
   ../Common/AArch64/ArmLibSupport.S
   ../Common/ArmLib.c
+  AArch64LibConstructor.c
 
 [Packages]
   ArmPkg/ArmPkg.dec
@@ -38,6 +40,7 @@ [Packages]
 
 [LibraryClasses]
   MemoryAllocationLib
+  CacheMaintenanceLib
 
 [Protocols]
   gEfiCpuArchProtocolGuid
diff --git a/ArmPkg/Library/ArmLib/AArch64/AArch64LibConstructor.c b/ArmPkg/Library/ArmLib/AArch64/AArch64LibConstructor.c
new file mode 100644
index 000000000000..d2d0d3c15ee3
--- /dev/null
+++ b/ArmPkg/Library/ArmLib/AArch64/AArch64LibConstructor.c
@@ -0,0 +1,36 @@
+#/* @file
+#
+#  Copyright (c) 2016, Linaro Limited. All rights reserved.
+#
+#  This program and the accompanying materials
+#  are licensed and made available under the terms and conditions of the BSD License
+#  which accompanies this distribution.  The full text of the license may be found at
+#  http://opensource.org/licenses/bsd-license.php
+#
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#*/
+
+#include <Base.h>
+
+#include <Library/ArmLib.h>
+#include <Library/CacheMaintenanceLib.h>
+
+RETURN_STATUS
+EFIAPI
+AArch64LibConstructor (
+  VOID
+  )
+{
+  extern UINT32 ArmReplaceLiveTranslationEntrySize;
+
+  //
+  // The ArmReplaceLiveTranslationEntry () helper function may be invoked
+  // with the MMU off so we have to ensure that it gets cleaned to the PoC
+  //
+  WriteBackDataCacheRange (ArmReplaceLiveTranslationEntry,
+    ArmReplaceLiveTranslationEntrySize);
+
+  return RETURN_SUCCESS;
+}
diff --git a/ArmPkg/Library/ArmLib/AArch64/AArch64Mmu.c b/ArmPkg/Library/ArmLib/AArch64/AArch64Mmu.c
index b7d23c6f3286..2cc6fc45aecf 100644
--- a/ArmPkg/Library/ArmLib/AArch64/AArch64Mmu.c
+++ b/ArmPkg/Library/ArmLib/AArch64/AArch64Mmu.c
@@ -169,6 +169,20 @@ GetRootTranslationTableInfo (
 
 STATIC
 VOID
+ReplaceLiveEntry (
+  IN  UINT64  *Entry,
+  IN  UINT64  Value
+  )
+{
+  if (!ArmMmuEnabled ()) {
+    *Entry = Value;
+  } else {
+    ArmReplaceLiveTranslationEntry (Entry, Value);
+  }
+}
+
+STATIC
+VOID
 LookupAddresstoRootTable (
   IN  UINT64  MaxAddress,
   OUT UINTN  *T0SZ,
@@ -330,7 +344,8 @@ GetBlockEntryListFromAddress (
         }
 
         // Fill the BlockEntry with the new TranslationTable
-        *BlockEntry = ((UINTN)TranslationTable & TT_ADDRESS_MASK_DESCRIPTION_TABLE) | TableAttributes | TT_TYPE_TABLE_ENTRY;
+        ReplaceLiveEntry (BlockEntry,
+          ((UINTN)TranslationTable & TT_ADDRESS_MASK_DESCRIPTION_TABLE) | TableAttributes | TT_TYPE_TABLE_ENTRY);
       }
     } else {
       if (IndexLevel != PageLevel) {
diff --git a/ArmPkg/Library/ArmLib/AArch64/AArch64Support.S b/ArmPkg/Library/ArmLib/AArch64/AArch64Support.S
index 1a3023b79487..789436b650df 100644
--- a/ArmPkg/Library/ArmLib/AArch64/AArch64Support.S
+++ b/ArmPkg/Library/ArmLib/AArch64/AArch64Support.S
@@ -56,6 +56,8 @@ GCC_ASM_EXPORT (ArmReadIdPfr1)
 GCC_ASM_EXPORT (ArmWriteHcr)
 GCC_ASM_EXPORT (ArmReadHcr)
 GCC_ASM_EXPORT (ArmReadCurrentEL)
+GCC_ASM_EXPORT (ArmReplaceLiveTranslationEntry)
+GCC_ASM_EXPORT (ArmReplaceLiveTranslationEntrySize)
 
 .set CTRL_M_BIT,      (1 << 0)
 .set CTRL_A_BIT,      (1 << 1)
@@ -481,4 +483,53 @@ ASM_PFX(ArmReadCurrentEL):
   mrs   x0, CurrentEL
   ret
 
+//VOID
+//ArmReplaceLiveTranslationEntry (
+//  IN  UINT64  *Entry,
+//  IN  UINT64  Value
+//  )
+ASM_PFX(ArmReplaceLiveTranslationEntry):
+  .macro __replace_entry, el
+  mrs   x8, sctlr_el\el
+  and   x9, x8, #~CTRL_M_BIT  // Clear MMU enable bit
+  msr   sctlr_el\el, x9
+  isb
+
+  // write an invalid entry and invalidate it in the caches
+  str   xzr, [x0]
+  dmb   sy
+  dc    ivac, x0
+  .if   \el == 1
+  tlbi  vmalle1
+  .else
+  tlbi  alle\el
+  .endif
+  dsb   sy
+  msr   sctlr_el\el, x8
+  isb
+  .endm
+
+  // disable interrupts
+  mrs   x2, daif
+  msr   daifset, #0xf
+  isb
+
+  // clean and invalidate first so that we don't clobber adjacent entries
+  // that are dirty in the caches
+  dc    civac, x0
+  dsb   ish
+
+  EL1_OR_EL2_OR_EL3(x3)
+1:__replace_entry 1
+  b     4f
+2:__replace_entry 2
+  b     4f
+3:__replace_entry 3
+4:msr   daif, x2
+  str   x1, [x0]
+  ret
+
+ASM_PFX(ArmReplaceLiveTranslationEntrySize):
+   .long    . - ArmReplaceLiveTranslationEntry
+
 ASM_FUNCTION_REMOVE_IF_UNREFERENCED
