diff --git a/chrome/browser/smart_card/smart_card_permission_request.cc b/chrome/browser/smart_card/smart_card_permission_request.cc
index c54e3aa1f6a9c..6c975a0874da9 100644
--- a/chrome/browser/smart_card/smart_card_permission_request.cc
+++ b/chrome/browser/smart_card/smart_card_permission_request.cc
@@ -39,6 +39,11 @@ std::u16string SmartCardPermissionRequest::GetMessageTextFragment() const {
                                     base::ASCIIToUTF16(reader_name_));
 }
 
+std::optional<std::u16string> SmartCardPermissionRequest::GetAllowAlwaysText()
+    const {
+  return l10n_util::GetStringUTF16(IDS_SMART_CARD_PERMISSION_ALWAYS_ALLOW);
+}
+
 void SmartCardPermissionRequest::OnPermissionDecided(
     ContentSetting content_setting_result,
     bool is_one_time,
diff --git a/chrome/browser/smart_card/smart_card_permission_request.h b/chrome/browser/smart_card/smart_card_permission_request.h
index 27d9c1e6acb52..c5e1685345e20 100644
--- a/chrome/browser/smart_card/smart_card_permission_request.h
+++ b/chrome/browser/smart_card/smart_card_permission_request.h
@@ -31,6 +31,7 @@ class SmartCardPermissionRequest : public permissions::PermissionRequest {
   bool IsDuplicateOf(
       permissions::PermissionRequest* other_request) const override;
   std::u16string GetMessageTextFragment() const override;
+  std::optional<std::u16string> GetAllowAlwaysText() const override;
 
   void OnPermissionDecided(ContentSetting result,
                            bool is_one_time,
diff --git a/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.cc b/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.cc
index 5d10b466b0574..0329b458dfe9d 100644
--- a/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.cc
+++ b/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.cc
@@ -73,7 +73,8 @@ PermissionPromptBubbleBaseView::PermissionPromptBubbleBaseView(
 
 PermissionPromptBubbleBaseView::~PermissionPromptBubbleBaseView() = default;
 
-void PermissionPromptBubbleBaseView::CreatePermissionButtons() {
+void PermissionPromptBubbleBaseView::CreatePermissionButtons(
+    const std::u16string& allow_always_text) {
   if (is_one_time_permission_) {
     SetButtons(ui::DIALOG_BUTTON_NONE);
 
@@ -95,7 +96,7 @@ void PermissionPromptBubbleBaseView::CreatePermissionButtons() {
                                 FilterUnintenedEventsAndRunCallbacks,
                             base::Unretained(this),
                             GetViewId(PermissionDialogButton::kAccept)),
-        l10n_util::GetStringUTF16(IDS_PERMISSION_ALLOW_EVERY_VISIT));
+        allow_always_text);
     allow_always_button->SetProperty(views::kElementIdentifierKey,
                                      kAllowButtonElementId);
     allow_always_button->SetID(GetViewId(PermissionDialogButton::kAccept));
@@ -299,6 +300,21 @@ bool PermissionPromptBubbleBaseView::IsOneTimePermission(
   return true;
 }
 
+std::u16string PermissionPromptBubbleBaseView::GetAllowAlwaysText(
+    const std::vector<permissions::PermissionRequest*>& visible_requests) {
+  CHECK_GT(visible_requests.size(), 0u);
+
+  if (visible_requests.size() == 1 &&
+      visible_requests[0]->GetAllowAlwaysText().has_value()) {
+    // A prompt for a single request can use an "allow always" text that is
+    // customized for it.
+    return visible_requests[0]->GetAllowAlwaysText().value();
+  }
+
+  // Use the generic text.
+  return l10n_util::GetStringUTF16(IDS_PERMISSION_ALLOW_EVERY_VISIT);
+}
+
 void PermissionPromptBubbleBaseView::RecordDecision(
     permissions::PermissionAction action) {
   const std::string uma_suffix =
diff --git a/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.h b/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.h
index f562d38d6a5a6..949df6630ba32 100644
--- a/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.h
+++ b/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.h
@@ -82,7 +82,7 @@ class PermissionPromptBubbleBaseView : public PermissionPromptBaseView {
   std::u16string GetPermissionFragmentForTesting() const;
 
  protected:
-  void CreatePermissionButtons();
+  void CreatePermissionButtons(const std::u16string& allow_always_text);
   void CreateExtraTextLabel(const std::u16string& extra_text);
 
   void CreateWidget();
@@ -97,6 +97,9 @@ class PermissionPromptBubbleBaseView : public PermissionPromptBaseView {
   static bool IsOneTimePermission(
       permissions::PermissionPrompt::Delegate& delegate);
 
+  static std::u16string GetAllowAlwaysText(
+      const std::vector<permissions::PermissionRequest*>& visible_requests);
+
  private:
   void SetPromptStyle(PermissionPromptStyle prompt_style);
 
diff --git a/chrome/browser/ui/views/permissions/permission_prompt_bubble_one_origin_view.cc b/chrome/browser/ui/views/permissions/permission_prompt_bubble_one_origin_view.cc
index c84a2711f9761..218cfcf1581ad 100644
--- a/chrome/browser/ui/views/permissions/permission_prompt_bubble_one_origin_view.cc
+++ b/chrome/browser/ui/views/permissions/permission_prompt_bubble_one_origin_view.cc
@@ -172,7 +172,7 @@ PermissionPromptBubbleOneOriginView::PermissionPromptBubbleOneOriginView(
     CreateExtraTextLabel(extra_text.value());
   }
 
-  CreatePermissionButtons();
+  CreatePermissionButtons(GetAllowAlwaysText(visible_requests));
 
   bool has_camera_request = false;
   bool has_mic_request = false;
diff --git a/chrome/browser/ui/views/permissions/permission_prompt_bubble_two_origins_view.cc b/chrome/browser/ui/views/permissions/permission_prompt_bubble_two_origins_view.cc
index a53eeb983b765..c9bc577faefc0 100644
--- a/chrome/browser/ui/views/permissions/permission_prompt_bubble_two_origins_view.cc
+++ b/chrome/browser/ui/views/permissions/permission_prompt_bubble_two_origins_view.cc
@@ -67,7 +67,7 @@ PermissionPromptBubbleTwoOriginsView::PermissionPromptBubbleTwoOriginsView(
     CreateExtraTextLabel(extra_text.value());
   }
 
-  CreatePermissionButtons();
+  CreatePermissionButtons(GetAllowAlwaysText(delegate->Requests()));
 
   // Only requests for Storage Access should use this prompt.
   CHECK(delegate);
diff --git a/components/permissions/permission_request.cc b/components/permissions/permission_request.cc
index 824a1517c764e..4d07c0172634c 100644
--- a/components/permissions/permission_request.cc
+++ b/components/permissions/permission_request.cc
@@ -282,6 +282,10 @@ std::u16string PermissionRequest::GetMessageTextFragment() const {
 }
 #endif
 
+std::optional<std::u16string> PermissionRequest::GetAllowAlwaysText() const {
+  return std::nullopt;
+}
+
 bool PermissionRequest::ShouldUseTwoOriginPrompt() const {
   return request_type() == RequestType::kStorageAccess &&
          base::FeatureList::IsEnabled(
diff --git a/components/permissions/permission_request.h b/components/permissions/permission_request.h
index 4ae1ca299ec5f..bbbe227327a58 100644
--- a/components/permissions/permission_request.h
+++ b/components/permissions/permission_request.h
@@ -116,6 +116,12 @@ class PermissionRequest {
   virtual std::u16string GetMessageTextFragment() const;
 #endif
 
+  // Returns the text to be used in the "allow always" button of the
+  // permission prompt.
+  // If not provided, the generic text for this button will be used instead.
+  // The default implementation returns std::nullopt (ie, use generic text).
+  virtual std::optional<std::u16string> GetAllowAlwaysText() const;
+
   // Whether the request was initiated by the user clicking on the permission
   // element.
   bool IsEmbeddedPermissionElementInitiated() const;
diff --git a/components/permissions_strings.grdp b/components/permissions_strings.grdp
index 8538d4c5319c0..54778c8171ab3 100644
--- a/components/permissions_strings.grdp
+++ b/components/permissions_strings.grdp
@@ -345,6 +345,9 @@ This will otherwise be blocked by your privacy settings. This will allow the con
     <message name="IDS_SMART_CARD_PERMISSION_PROMPT" desc="Text on dialog that asks the user for permission to access a smart card reader device and the card inserted in it (or presented to it, if contactless).">
       Control <ph name="ReaderName">$1<ex>HID Omnikey</ex></ph> and gain access to the smart card accessible to it?
     </message>
+    <message name="IDS_SMART_CARD_PERMISSION_ALWAYS_ALLOW" desc="Label on button to always allow access to this smart card reader and any card inserted in (or presented to) it.">
+      Always allow, with any card
+    </message>
   </if>
 
   <!-- Quota messages -->
diff --git a/components/permissions_strings_grdp/IDS_SMART_CARD_PERMISSION_ALWAYS_ALLOW.png.sha1 b/components/permissions_strings_grdp/IDS_SMART_CARD_PERMISSION_ALWAYS_ALLOW.png.sha1
new file mode 100644
index 0000000000000..b33a09c8d53d4
--- /dev/null
+++ b/components/permissions_strings_grdp/IDS_SMART_CARD_PERMISSION_ALWAYS_ALLOW.png.sha1
@@ -0,0 +1 @@
+3e0e67dcb269c255fe09bd916423511c60eb9d10
\ No newline at end of file