Maybe,
^(?:40\d[0-5]|[1-3]\d{3}|\d{1,3}),(?:40\d[0-5]|[1-3]\d{3}|\d{1,3}),(?:40\d[0-5]|[1-3]\d{3}|\d{1,3}),(?:40\d[0-5]|[1-3]\d{3}|\d{1,3})$
might work OK, if 000,000,000,000 would be valid, otherwise,
^(?:(?:40\d[0-5]|[1-3]\d{3}|[1-9]\d{2}|[1-9]\d|\d),){3}(?:40\d[0-5]|[1-3]\d{3}|[1-9]\d{2}|[1-9]\d|\d)$
might be an option too.
Test
using System;
using System.Text.RegularExpressions;
public class Example
{
public static void Main()
{
string pattern = @"^(?:(?:40\d[0-5]|[1-3]\d{3}|[1-9]\d{2}|[1-9]\d|\d),){3}(?:40\d[0-5]|[1-3]\d{3}|[1-9]\d{2}|[1-9]\d|\d)$";
string input = @"1200,2500,6500,90
1200,2500,6500,90
1200,2500,4095,90
0,0,0,0
999,1,0,99
000,000,000,000
4095,4095,4095,4095
";
RegexOptions options = RegexOptions.Multiline;
foreach (Match m in Regex.Matches(input, pattern, options))
{
Console.WriteLine("'{0}' found at index {1}.", m.Value, m.Index);
}
}
}
If you wish to simplify/modify/explore the expression, it's been explained on the top right panel of regex101.com. If you'd like, you can also watch in this link, how it would match against some sample inputs.
RegEx Circuit
jex.im visualizes regular expressions:

\b. I came up with^(?:(?:40\d[0-5]|[1-3]\d{3}|[1-9]\d?\d?|0),?\b){4}$