diff --git a/arch/x86/include/asm/keylocker.h b/arch/x86/include/asm/keylocker.h
index daf0734a4095..722574c305c2 100644
--- a/arch/x86/include/asm/keylocker.h
+++ b/arch/x86/include/asm/keylocker.h
@@ -6,6 +6,7 @@
 #ifndef __ASSEMBLY__
 
 #include <linux/bits.h>
+#include <asm/msr.h>
 
 #define KEYLOCKER_CPUID                0x019
 #define KEYLOCKER_CPUID_EAX_SUPERVISOR BIT(0)
@@ -25,5 +26,16 @@ void invalidate_keylocker_data(void);
 #define invalidate_keylocker_data() do { } while (0)
 #endif
 
+static inline u64 read_keylocker_backup_status(void)
+{
+	u64 status;
+
+	rdmsrl(MSR_IA32_IWKEYBACKUP_STATUS, status);
+	return status;
+}
+
+void backup_keylocker(void);
+bool copy_keylocker(void);
+
 #endif /*__ASSEMBLY__ */
 #endif /* _ASM_KEYLOCKER_H */
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index d675075848bb..a446d5aff08f 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -463,24 +463,35 @@ __setup("nofsgsbase", x86_nofsgsbase_setup);
 
 static __always_inline void setup_keylocker(struct cpuinfo_x86 *c)
 {
-	bool keyloaded;
-
 	if (!cpu_feature_enabled(X86_FEATURE_KEYLOCKER))
 		goto out;
 
 	cr4_set_bits(X86_CR4_KEYLOCKER);
 
 	if (c == &boot_cpu_data) {
+		bool keyloaded;
+
 		if (!check_keylocker_readiness())
 			goto disable_keylocker;
 
 		make_keylocker_data();
-	}
 
-	keyloaded = load_keylocker();
-	if (!keyloaded) {
-		pr_err_once("x86/keylocker: Failed to load internal key\n");
-		goto disable_keylocker;
+		keyloaded = load_keylocker();
+		if (!keyloaded) {
+			pr_err("x86/keylocker: Fail to load internal key\n");
+			goto disable_keylocker;
+		}
+
+		backup_keylocker();
+	} else {
+		bool keycopied;
+
+		/* NB: When system wakes up, this path recovers the internal key. */
+		keycopied = copy_keylocker();
+		if (!keycopied) {
+			pr_err_once("x86/keylocker: Fail to copy internal key\n");
+			goto disable_keylocker;
+		}
 	}
 
 	pr_info_once("x86/keylocker: Activated\n");
diff --git a/arch/x86/kernel/keylocker.c b/arch/x86/kernel/keylocker.c
index e455d806b80c..229875ac80d5 100644
--- a/arch/x86/kernel/keylocker.c
+++ b/arch/x86/kernel/keylocker.c
@@ -5,11 +5,15 @@
  */
 
 #include <linux/random.h>
+#include <linux/acpi.h>
+#include <linux/delay.h>
 
 #include <asm/keylocker.h>
 #include <asm/fpu/types.h>
 #include <asm/fpu/api.h>
 
+static bool keybackup_available;
+
 bool check_keylocker_readiness(void)
 {
 	u32 eax, ebx, ecx, edx;
@@ -21,6 +25,14 @@ bool check_keylocker_readiness(void)
 		return false;
 	}
 
+	keybackup_available = (ebx & KEYLOCKER_CPUID_EBX_BACKUP);
+	/* Internal Key backup is essential with S3/4 states */
+	if (!keybackup_available &&
+	    (acpi_sleep_state_supported(ACPI_STATE_S3) ||
+	     acpi_sleep_state_supported(ACPI_STATE_S4))) {
+		pr_debug("x86/keylocker: no key backup support with possible S3/4\n");
+		return false;
+	}
 	return true;
 }
 
@@ -29,6 +41,7 @@ bool check_keylocker_readiness(void)
 #define LOADIWKEY_NUM_OPERANDS	3
 
 static struct key {
+	bool valid;
 	struct reg_128_bit value[LOADIWKEY_NUM_OPERANDS];
 } keydata;
 
@@ -38,11 +51,15 @@ void make_keylocker_data(void)
 
 	for (i = 0; i < LOADIWKEY_NUM_OPERANDS; i++)
 		get_random_bytes(&keydata.value[i], sizeof(struct reg_128_bit));
+
+	keydata.valid = true;
 }
 
 void invalidate_keylocker_data(void)
 {
 	memset(&keydata.value, 0, sizeof(struct reg_128_bit) * LOADIWKEY_NUM_OPERANDS);
+
+	keydata.valid = false;
 }
 
 #define USE_SWKEY	0
@@ -69,3 +86,37 @@ bool load_keylocker(void)
 
 	return err ? false : true;
 }
+
+void backup_keylocker(void)
+{
+	if (keybackup_available)
+		wrmsrl(MSR_IA32_COPY_LOCAL_TO_PLATFORM, 1);
+}
+
+#define KEYRESTORE_RETRY	1
+
+bool copy_keylocker(void)
+{
+	bool copied = false;
+	int i;
+
+	/* Use valid key data when available */
+	if (keydata.valid)
+		return load_keylocker();
+
+	if (!keybackup_available)
+		return copied;
+
+	wrmsrl(MSR_IA32_COPY_PLATFORM_TO_LOCAL, 1);
+
+	for (i = 0; (i <= KEYRESTORE_RETRY) && !copied; i++) {
+		u64 status;
+
+		if (i)
+			udelay(1);
+		rdmsrl(MSR_IA32_COPY_STATUS, status);
+		copied = status & BIT(0) ? true : false;
+	}
+
+	return copied;
+}
diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu.c
index db1378c6ff26..5412440e7c5c 100644
--- a/arch/x86/power/cpu.c
+++ b/arch/x86/power/cpu.c
@@ -25,6 +25,7 @@
 #include <asm/cpu.h>
 #include <asm/mmu_context.h>
 #include <asm/cpu_device_id.h>
+#include <asm/keylocker.h>
 
 #ifdef CONFIG_X86_32
 __visible unsigned long saved_context_ebx;
@@ -57,6 +58,38 @@ static void msr_restore_context(struct saved_context *ctxt)
 	}
 }
 
+/*
+ * The boot CPU executes this function, while other CPUs restore the key
+ * through the setup path in setup_keylocker().
+ */
+static void restore_keylocker(void)
+{
+	u64 keybackup_status;
+	bool keycopied;
+
+	if (!cpu_feature_enabled(X86_FEATURE_KEYLOCKER))
+		return;
+
+	keybackup_status = read_keylocker_backup_status();
+	if (!(keybackup_status & BIT(0))) {
+		pr_err("x86/keylocker: internal key restoration failed with %s\n",
+		       (keybackup_status & BIT(2)) ? "read error" : "invalid status");
+		WARN_ON(1);
+		goto disable_keylocker;
+	}
+
+	keycopied = copy_keylocker();
+	if (keycopied)
+		return;
+
+	pr_err("x86/keylocker: internal key copy failure\n");
+
+disable_keylocker:
+	pr_info("x86/keylocker: Disabled with internal key restoration failure\n");
+	setup_clear_cpu_cap(X86_FEATURE_KEYLOCKER);
+	cr4_clear_bits(X86_CR4_KEYLOCKER);
+}
+
 /**
  *	__save_processor_state - save CPU registers before creating a
  *		hibernation image and before restoring the memory state from it
@@ -265,6 +298,7 @@ static void notrace __restore_processor_state(struct saved_context *ctxt)
 	mtrr_bp_restore();
 	perf_restore_debug_store();
 	msr_restore_context(ctxt);
+	restore_keylocker();
 
 	c = &cpu_data(smp_processor_id());
 	if (cpu_has(c, X86_FEATURE_MSR_IA32_FEAT_CTL))
