diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c b/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c
index 6fde3b2..2944707 100644
--- a/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c
+++ b/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c
@@ -71,6 +71,7 @@ TERMINAL_DEV  mTerminalDevTemplate = {
   },
   NULL, // TerminalConsoleModeData
   0,  // SerialInTimeOut
+  0,  // KeyboardTimerInterval
 
   NULL, // RawFifo
   NULL, // UnicodeFiFo
@@ -984,10 +985,12 @@ TerminalDriverBindingStart (
                     );
     ASSERT_EFI_ERROR (Status);
 
+    TerminalDevice->KeyboardTimerInterval = GetKeyboardTimerInterval (Mode);
+
     Status = gBS->SetTimer (
                     TerminalDevice->TimerEvent,
                     TimerPeriodic,
-                    KEYBOARD_TIMER_INTERVAL
+                    TerminalDevice->KeyboardTimerInterval
                     );
     ASSERT_EFI_ERROR (Status);
 
diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h b/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h
index 269d2ae..a1ff595 100644
--- a/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h
+++ b/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h
@@ -28,6 +28,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include <Protocol/DevicePath.h>
 #include <Protocol/SimpleTextIn.h>
 #include <Protocol/SimpleTextInEx.h>
+#include <Protocol/Timer.h>
 
 #include <Library/DebugLib.h>
 #include <Library/UefiDriverEntryPoint.h>
@@ -68,8 +69,6 @@ typedef struct {
   UINTN   Rows;
 } TERMINAL_CONSOLE_MODE_DATA;
 
-#define KEYBOARD_TIMER_INTERVAL         200000  // 0.02s
-
 #define TERMINAL_DEV_SIGNATURE  SIGNATURE_32 ('t', 'm', 'n', 'l')
 
 #define TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE SIGNATURE_32 ('t', 'm', 'e', 'n')
@@ -91,6 +90,7 @@ typedef struct {
   EFI_SIMPLE_TEXT_OUTPUT_MODE         SimpleTextOutputMode;
   TERMINAL_CONSOLE_MODE_DATA          *TerminalConsoleModeData;
   UINTN                               SerialInTimeOut;
+  UINT64                              KeyboardTimerInterval;
   RAW_DATA_FIFO                       *RawFiFo;
   UNICODE_FIFO                        *UnicodeFiFo;
   EFI_KEY_FIFO                        *EfiKeyFiFo;
@@ -1358,4 +1358,28 @@ TerminalConInTimerHandler (
   IN EFI_EVENT            Event,
   IN VOID                 *Context
   );
+
+/**
+  Calculate input polling timer interval by serial IO mode.
+
+  @param  Mode                  Pointer to serial IO mode.
+
+  @retval The required polling timer interval in 100ns.
+
+**/
+UINT64
+GetKeyboardTimerInterval (
+  IN EFI_SERIAL_IO_MODE   *Mode
+  );
+
+/**
+  Update period of polling timer event.
+
+  @param  TerminalDevice        The terminal device to update.
+**/
+VOID
+UpdatePollingRate (
+  IN TERMINAL_DEV         *TerminalDevice
+  );
+
 #endif
diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c b/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c
index 3be877b..e7788a0 100644
--- a/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c
+++ b/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c
@@ -15,6 +15,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 
 #include "Terminal.h"
 
+EFI_TIMER_ARCH_PROTOCOL *gTimer;
 
 /**
   Reads the next keystroke from the input device. The WaitForKey Event can
@@ -502,6 +503,94 @@ TerminalConInWaitForKey (
 }
 
 /**
+  Calculate input polling timer interval by serial IO mode.
+
+  @param  Mode                  Pointer to serial IO mode.
+
+  @retval The required polling timer interval in 100ns.
+
+**/
+UINT64
+GetKeyboardTimerInterval (
+  IN EFI_SERIAL_IO_MODE *Mode
+  )
+{
+  UINT32                FifoDepth;
+  UINT64                BaudRate;
+  UINT64                Interval;
+  UINT64                TimerPeriod;
+  EFI_STATUS            Status;
+
+  // Make some assumption if the values are not suitable for calculating.
+  BaudRate = Mode->BaudRate;
+  if (BaudRate == 0) {
+    BaudRate = 115200;
+  }
+  FifoDepth = Mode->ReceiveFifoDepth;
+  if (FifoDepth == 0) {
+    FifoDepth = 1;
+  }
+
+  // We assume stop bits to be 1 and ignore parity bit to make it simple
+  // and fast enough to poll.
+  Interval = DivU64x64Remainder (
+    FifoDepth * (1 + Mode->DataBits + 1) * 10000000,
+    Mode->BaudRate,
+    NULL
+    );
+
+  // As this is a time sensitive event, we still need to align the
+  // interval to timer interrupt period.
+  if (gTimer == NULL) {
+    Status = gBS->LocateProtocol (
+        &gEfiTimerArchProtocolGuid,
+        EFI_NATIVE_INTERFACE,
+        (VOID **) &gTimer
+        );
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  Status = gTimer->GetTimerPeriod (gTimer, &TimerPeriod);
+  ASSERT_EFI_ERROR (Status);
+
+  if (Interval <= TimerPeriod) {
+    return TimerPeriod;
+  }
+  return MultU64x64 (DivU64x64Remainder (Interval, TimerPeriod, NULL), TimerPeriod);
+}
+
+
+/**
+  Update period of polling timer event.
+
+  @param  TerminalDevice        The terminal device to update.
+**/
+VOID
+UpdatePollingRate (
+  IN TERMINAL_DEV         *TerminalDevice
+  )
+{
+  UINT64                  NewInterval;
+  EFI_STATUS              Status;
+
+  NewInterval = GetKeyboardTimerInterval (TerminalDevice->SerialIo->Mode);
+
+  if (TerminalDevice->KeyboardTimerInterval == NewInterval) {
+    return;
+  }
+
+  Status = gBS->SetTimer (
+                  TerminalDevice->TimerEvent,
+                  TimerPeriodic,
+                  NewInterval
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  TerminalDevice->KeyboardTimerInterval = NewInterval;
+}
+
+
+/**
   Timer handler to poll the key from serial.
 
   @param  Event                    Indicates the event that invoke this function.
@@ -560,6 +649,9 @@ TerminalConInTimerHandler (
       TerminalDevice->SerialInTimeOut = SerialInTimeOut;
     }
   }
+
+  UpdatePollingRate (TerminalDevice);
+
   //
   // Check whether serial buffer is empty.
   // Skip the key transfer loop only if the SerialIo protocol instance
diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf b/MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf
index 0780296..dfd5035 100644
--- a/MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf
+++ b/MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf
@@ -84,6 +84,7 @@
   gEfiSimpleTextInProtocolGuid                  ## BY_START
   gEfiSimpleTextInputExProtocolGuid             ## BY_START
   gEfiSimpleTextOutProtocolGuid                 ## BY_START
+  gEfiTimerArchProtocolGuid                     ## CONSUMES
 
 [Pcd]
   gEfiMdePkgTokenSpaceGuid.PcdDefaultTerminalType           ## SOMETIMES_CONSUMES
