diff --git a/x/auth/tx/config.go b/x/auth/tx/config.go
index 0ebeba9b3534..ae1144a909af 100644
--- a/x/auth/tx/config.go
+++ b/x/auth/tx/config.go
@@ -27,21 +27,21 @@ type config struct {
 // NOTE: Use NewTxConfigWithHandler to provide a custom signing handler in case the sign mode
 // is not supported by default (eg: SignMode_SIGN_MODE_EIP_191). Use NewTxConfigWithTextual
 // to enable SIGN_MODE_TEXTUAL (for testing purposes for now).
-func NewTxConfig(protoCodec codec.ProtoCodecMarshaler, enabledSignModes []signingtypes.SignMode) client.TxConfig {
+func NewTxConfig(protoCodec codec.ProtoCodecMarshaler, enabledSignModes []signingtypes.SignMode, customSignModes ...signing.SignModeHandler) client.TxConfig {
 	for _, m := range enabledSignModes {
 		if m == signingtypes.SignMode_SIGN_MODE_TEXTUAL {
 			panic("cannot use NewTxConfig with SIGN_MODE_TEXTUAL enabled; please use NewTxConfigWithTextual")
 		}
 	}
 
-	return NewTxConfigWithHandler(protoCodec, makeSignModeHandler(enabledSignModes, &textual.SignModeHandler{}))
+	return NewTxConfigWithHandler(protoCodec, makeSignModeHandler(enabledSignModes, &textual.SignModeHandler{}, customSignModes...))
 }
 
 // NewTxConfigWithTextual is like NewTxConfig with the ability to add
 // a SIGN_MODE_TEXTUAL renderer. It is currently still EXPERIMENTAL, for should
 // be used for TESTING purposes only, until Textual is fully released.
-func NewTxConfigWithTextual(protoCodec codec.ProtoCodecMarshaler, enabledSignModes []signingtypes.SignMode, textual *textual.SignModeHandler) client.TxConfig {
-	return NewTxConfigWithHandler(protoCodec, makeSignModeHandler(enabledSignModes, textual))
+func NewTxConfigWithTextual(protoCodec codec.ProtoCodecMarshaler, enabledSignModes []signingtypes.SignMode, textual *textual.SignModeHandler, customSignModes ...signing.SignModeHandler) client.TxConfig {
+	return NewTxConfigWithHandler(protoCodec, makeSignModeHandler(enabledSignModes, textual, customSignModes...))
 }
 
 // NewTxConfig returns a new protobuf TxConfig using the provided ProtoCodec and signing handler.
diff --git a/x/auth/tx/config/config.go b/x/auth/tx/config/config.go
index 1a7265462366..cbb55b92c9f6 100644
--- a/x/auth/tx/config/config.go
+++ b/x/auth/tx/config/config.go
@@ -13,6 +13,7 @@ import (
 	sdk "github.com/cosmos/cosmos-sdk/types"
 	"github.com/cosmos/cosmos-sdk/x/auth/ante"
 	"github.com/cosmos/cosmos-sdk/x/auth/posthandler"
+	"github.com/cosmos/cosmos-sdk/x/auth/signing"
 	"github.com/cosmos/cosmos-sdk/x/auth/tx"
 	authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
 )
@@ -36,6 +37,8 @@ type TxInputs struct {
 	// TxBankKeeper is the expected bank keeper to be passed to Textual
 	TxBankKeeper   BankKeeper
 	FeeGrantKeeper ante.FeegrantKeeper `optional:"true"`
+
+	CustomSignModeHandlers func() []signing.SignModeHandler `optional:"true"`
 }
 
 //nolint:revive
@@ -48,7 +51,12 @@ type TxOutputs struct {
 
 func ProvideModule(in TxInputs) TxOutputs {
 	textual := NewTextualWithBankKeeper(in.TxBankKeeper)
-	txConfig := tx.NewTxConfigWithTextual(in.ProtoCodecMarshaler, tx.DefaultSignModes, textual)
+	var txConfig client.TxConfig
+	if in.CustomSignModeHandlers == nil {
+		txConfig = tx.NewTxConfigWithTextual(in.ProtoCodecMarshaler, tx.DefaultSignModes, textual)
+	} else {
+		txConfig = tx.NewTxConfigWithTextual(in.ProtoCodecMarshaler, tx.DefaultSignModes, textual, in.CustomSignModeHandlers()...)
+	}
 
 	baseAppOption := func(app *baseapp.BaseApp) {
 		// AnteHandlers
diff --git a/x/auth/tx/mode_handler.go b/x/auth/tx/mode_handler.go
index 8b0e79914cdf..30bc6b1c08bb 100644
--- a/x/auth/tx/mode_handler.go
+++ b/x/auth/tx/mode_handler.go
@@ -24,13 +24,14 @@ var DefaultSignModes = []signingtypes.SignMode{
 
 // makeSignModeHandler returns the default protobuf SignModeHandler supporting
 // SIGN_MODE_DIRECT, SIGN_MODE_DIRECT_AUX and SIGN_MODE_LEGACY_AMINO_JSON.
-func makeSignModeHandler(modes []signingtypes.SignMode, txt *textual.SignModeHandler) signing.SignModeHandler {
+func makeSignModeHandler(modes []signingtypes.SignMode, txt *textual.SignModeHandler, customSignModes ...signing.SignModeHandler) signing.SignModeHandler {
 	if len(modes) < 1 {
 		panic(fmt.Errorf("no sign modes enabled"))
 	}
 
-	handlers := make([]signing.SignModeHandler, len(modes))
+	handlers := make([]signing.SignModeHandler, len(modes)+len(customSignModes))
 
+	// handle cosmos-sdk defined sign modes
 	for i, mode := range modes {
 		switch mode {
 		case signingtypes.SignMode_SIGN_MODE_DIRECT:
@@ -46,6 +47,11 @@ func makeSignModeHandler(modes []signingtypes.SignMode, txt *textual.SignModeHan
 		}
 	}
 
+	// add custom sign modes
+	for i, handler := range customSignModes {
+		handlers[i+len(modes)] = handler
+	}
+
 	return signing.NewSignModeHandlerMap(
 		modes[0],
 		handlers,
diff --git a/x/tx/aminojson/internal/testpb/test.proto b/x/tx/aminojson/internal/testpb/test.proto
index 479436f1c4da..0b1b3644c843 100644
--- a/x/tx/aminojson/internal/testpb/test.proto
+++ b/x/tx/aminojson/internal/testpb/test.proto
@@ -11,36 +11,36 @@ import "google/protobuf/wrappers.proto";
 import "google/protobuf/field_mask.proto";
 import "google/protobuf/empty.proto";
 
-message WithAMap{
+message WithAMap {
   map<string, string> str_map = 1;
 }
 
-message WithAList{
-  repeated string dont_omitempty_list = 1 [ (amino.dont_omitempty) = true ];
-  repeated string list = 2;
+message WithAList {
+  repeated string dont_omitempty_list = 1 [(amino.dont_omitempty) = true];
+  repeated string list                = 2;
 }
 
 message ABitOfEverything {
   option (amino.name) = "ABitOfEverything";
 
   NestedMessage message = 1;
-  AnEnum enum = 2;
+  AnEnum enum           = 2;
 
   repeated int32 repeated = 6;
 
-  string str = 7;
-  bool bool = 8;
-  bytes bytes = 9;
-  int32 i32 = 10;
-  fixed32 f32 = 11;
-  uint32 u32 = 12;
-  sint32 si32 = 13;
-  sfixed32 sf32 = 14;
-  int64 i64 = 15;
-  fixed64 f64 = 16;
-  uint64 u64 = 17;
-  sint64 si64 = 18;
-  sfixed64 sf64 = 19;
+  string str     = 7;
+  bool bool      = 8;
+  bytes    bytes = 9;
+  int32    i32   = 10;
+  fixed32  f32   = 11;
+  uint32   u32   = 12;
+  sint32   si32  = 13;
+  sfixed32 sf32  = 14;
+  int64    i64   = 15;
+  fixed64  f64   = 16;
+  uint64   u64   = 17;
+  sint64   si64  = 18;
+  sfixed64 sf64  = 19;
 
   // The following types are not tested here because they are treated fundamentally differently in
   // gogoproto.  They are tested fully in /tests/integration/aminojson/aminojson_test.go
@@ -66,11 +66,11 @@ message NestedMessage {
   option (amino.name) = "NestedMessage";
 
   string foo = 1;
-  int32 bar = 2;
+  int32  bar = 2;
 }
 
 enum AnEnum {
   UNDEFINED = 0;
-  ONE = 1;
-  TWO = 2;
+  ONE       = 1;
+  TWO       = 2;
 }
\ No newline at end of file